//
// Created by xy on 2024/10/19.
//

#include "log.h"
#include "config.h"

// 全局日志对象定义
LogManager *g_log;

// 获取当前时间的简单实现

char* get_current_time() {
  static char buffer[20];
  struct timeval tv;
  gettimeofday(&tv, NULL);
  struct tm* tm_info = localtime(&tv.tv_sec);
  strftime(buffer, 20, "%Y-%m-%d %H:%M:%S", tm_info);
  return buffer;
}

int logLevel() {
  char* level = parseINI("level", NULL);
  int ret_level = INFO; // 默认值
  if (level) {
    if (strcmp(level, "DEBUG") == 0) {
      ret_level = DEBUG;
    } else if (strcmp(level, "WARN") == 0) {
      ret_level = WARN;
    } else if (strcmp(level, "ERROR") == 0) {
      ret_level = ERROR;
    }
    free(level); // 统一释放
  }
  return ret_level;
}


LogBase* initLogBase(char* path, LOGLEVEL level) {
  LogBase* log = (LogBase*)malloc(sizeof(LogBase));
  if (log == NULL) {
    printf("initLogBase malloc failed");
    return NULL;
  }

  FILE* file = fopen(path, "a");
  if (file == NULL) {
    printf("initLogBase fopen failed");
    free(log); // 释放内存
    return NULL;
  }

  log->path = strdup(path);
  log->file = file;
  log->level = level;
  log->file_count = 0;  // 初始化分片计数
  return log;
}

// 日志文件分片处理函数
void rotate_log(LogBase *log) {
  struct stat file_stat;
  if (fstat(fileno(log->file), &file_stat) == 0 && file_stat.st_size >= MAX_LOG_SIZE) {
    // 关闭当前文件
    fclose(log->file);

    // 构造新的日志文件名，基于计数器或时间戳
    char new_log_path[256];
    snprintf(new_log_path, sizeof(new_log_path), "%s.%d", log->path, ++log->file_count);

    // 打开新文件
    log->file = fopen(new_log_path, "a");
    if (log->file == NULL) {
      ERROR_LOG("rotate_log fopen failed");
    }
  }
}

// 清理超过五天的旧日志文件
void cleanup_old_logs(const char* directory) {
    DIR *dir = opendir(directory);
    struct dirent *entry;
    time_t now = time(NULL);
    const int days_to_keep = 5;
    //const long seconds_to_keep = days_to_keep * 24 * 3600;
    const long seconds_to_keep = days_to_keep * 2;

    if (dir) {
        while ((entry = readdir(dir)) != NULL) {
            if (entry->d_type == DT_REG) { // 仅处理常规文件
                char filepath[512];
                snprintf(filepath, sizeof(filepath), "%s/%s", directory, entry->d_name);
                struct stat file_stat;
                if (stat(filepath, &file_stat) == 0) {
                    if (now - file_stat.st_mtime > seconds_to_keep) {
                        remove(filepath); // 删除超过五天的日志文件
                    }
                }
            }
        }
        closedir(dir);
    }
}

// 初始化日志
bool initLog(int capacity) {
  g_log = (LogManager*)malloc(sizeof(LogManager));
  if (g_log == NULL) {
    ERROR_LOG("initLog malloc failed");
    return false;
  }
  g_log->main_level = logLevel();

  g_log->log[INFO - 1] = initLogBase("log/info.txt", INFO);
  g_log->log[DEBUG - 1] = initLogBase("log/debug.txt", DEBUG);
  g_log->log[WARN - 1] = initLogBase("log/warn.txt", WARN);
  g_log->log[ERROR - 1] = initLogBase("log/error.txt", ERROR);

  // 初始化队列
  g_log->queue = (ThreadSafeCircularQueue *) malloc(sizeof(ThreadSafeCircularQueue));
  if (!g_log->queue) {
    printf("Queue malloc failed");
    return false;
  }
  queue_init(g_log->queue, capacity);

  // 初始化条件变量
  if (pthread_cond_init(&g_log->cond_not_full, NULL) != 0) {
    printf("Condition variable init failed");
    return false;
  }
  if (pthread_cond_init(&g_log->cond_not_empty, NULL) != 0) {
    printf("Condition variable init failed");
    return false;
  }


  // 初始化锁
  if (pthread_mutex_init(&g_log->mutex, NULL) != 0) {
    printf("Mutex init failed");
    return false;
  }

  // 启动一个线程 异步执行任务，该函数为循环等待有任务来
  if (pthread_create(&g_log->task, NULL, async_write, NULL) != 0) {
    printf("Failed to create log writing thread");
    return false;
  }

  return true;
}


bool writeLog(char *data, LOGLEVEL log_level) {
  if (log_level < g_log->main_level) {
    return false;
  }

  printf("%s\n", data);

  ThreadParam *param = (ThreadParam *) malloc(sizeof(ThreadParam));
  if (param == NULL) {
    printf("ThreadParam malloc failed");
    return false;
  }
  param->log_level = log_level;
  strncpy(param->data, data, sizeof(param->data) - 1);
  param->data[sizeof(param->data) - 1] = '\0';  // 确保字符串以 NULL 结尾

  // 不再使用全局锁，队列本身线程安全
  if (!queue_push(g_log->queue, param)) {
    free(param);  // 如果推送失败，释放内存
    return false;
  }

  // 唤醒等待的消费者线程
  pthread_cond_signal(&g_log->cond_not_empty);

  return true;
}

void *async_write() {
  while (1) {
    pthread_mutex_lock(&g_log->mutex);

    // 等待队列非空
    while (queue_is_empty(g_log->queue)) {
      pthread_cond_wait(&g_log->cond_not_empty, &g_log->mutex);
    }

    ThreadParam *param = (ThreadParam *) queue_pop(g_log->queue);
    pthread_mutex_unlock(&g_log->mutex);

    if (!param) {
      continue;
    }

    LogBase* log = g_log->log[param->log_level - 1];
    if (log && log->file) {
      rotate_log(log);
      if (fprintf(log->file, "%s\n", param->data) < 0) {
        ERROR_LOG("Failed to write log");
      }
      fflush(log->file);
    }

    // 清理旧日志
    cleanup_old_logs("log");

    free(param);
  }
}



// 清理日志
void closeLog() {
  for (int i = 0; i < LOG_NUM; i++) {
    if (g_log->log[i]) {
      fclose(g_log->log[i]->file);
      free(g_log->log[i]->path);
      free(g_log->log[i]);
    }
  }

  // 释放队列
  free(g_log->queue);

  // 销毁条件变量和互斥锁
  pthread_cond_destroy(&g_log->cond_not_full);
  pthread_cond_destroy(&g_log->cond_not_empty);
  pthread_mutex_destroy(&g_log->mutex);

  free(g_log);
}
